package org.lgiavedoni.android.franq.service.phone;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import lombok.Getter;

import org.apache.commons.lang.StringUtils;
import org.lgiavedoni.android.franq.core.contact.Contact;
import org.lgiavedoni.android.franq.core.contact.ContactPhone;
import org.lgiavedoni.android.franq.core.service.Service;
import org.lgiavedoni.android.franq.util.string.StringUtil;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;

public class ContactService extends Service {

	public static final ContactService inst = new ContactService();

	@Getter(lazy=true)
	private final List<Contact> contacts = loadContacts();

	private List<Contact> loadContacts() {
		if (!ContextService.inst.isApplicationContextLoaded()) 
			return new ArrayList<Contact>();
		
		List<Contact> lContacts= new ArrayList<Contact>();
		ContentResolver cr = ContextService.inst.getApplicationContext().getContentResolver();
		Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
		if (cur.getCount() > 0) {
			while (cur.moveToNext()) {
				Contact contact = new Contact();
				String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
				String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
				contact.setName(name);
				
				if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
					Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
							new String[] { id }, null);
					while (pCur.moveToNext()) {
						String phoneNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
						int type = pCur.getInt(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
						// Remove the empty spaces in the number
						phoneNumber = StringUtils.remove(phoneNumber, " ");
						contact.addPhone(phoneNumber, type);
					}
					pCur.close();
				}
				lContacts.add(contact);
			}
		}
		return lContacts;

	}
	
	public List<Contact> getContactsIgnoreJustMail(List<Contact> contacts) {
		List<Contact> l = new ArrayList<Contact>();
		for(Contact c:contacts){
			if(!c.isJustMail()) 
				l.add(c);
		}
		return l;
	}
	
	public List<Contact> getContactsWithPhone(List<Contact> contacts) {
		List<Contact> l = new ArrayList<Contact>();
		for(Contact c:contacts){
			if(c.getPhones().size()>0) 
				l.add(c);
		}
		return l;
	}

	
	public List<Contact> getContactsByName(final String name) {
		return getContactsByName(getContacts(), name);
	}
		
	public List<Contact> getContactsByName(List<Contact> contacts, final String name) {	

		List<Contact> result = new ArrayList<Contact>();
		final Map<Integer, Integer> distances = new HashMap<Integer, Integer>();

		String[] searchTokens = name.split(" ");
		int total = 0;

		Iterator<Contact> iterator = null;
		String[] nameTokens = null;
		Contact aux = null;

		int minimum = Integer.MAX_VALUE;
		int distance = 0;
		int delta = 0;
		int temp = Integer.MAX_VALUE;

		for (Contact contact : contacts) {

			nameTokens = contact.getName().replaceAll("[^\\d\\w\\s]", "").replaceAll("\\s{2}", " ").split(" ");
			total = 0;

			for (int i = 0; i < searchTokens.length; i++) {
				temp = Integer.MAX_VALUE;
				for (int j = 0; j < nameTokens.length; j++) {
					distance = StringUtil.getDifference(searchTokens[i].toLowerCase(),
							searchTokens[i].length() < nameTokens[j].length() ? nameTokens[j].substring(0, searchTokens[i].length()).toLowerCase() : nameTokens[j].toLowerCase());
					temp = distance < temp ? distance : temp;
					if (temp == 0)
						break;
				}
				total += temp;
			}

			distance = total;
			delta = (int) Math.abs(distance * 40.0d / 100.0d);

			if (distance < minimum) {
				iterator = result.iterator();
				while (iterator.hasNext()) {
					aux = iterator.next();
					if (distances.get(aux.hashCode()).compareTo(Integer.valueOf(distance + delta)) > 0)
						iterator.remove();
				}

				distances.put(Integer.valueOf(contact.hashCode()), Integer.valueOf(distance));
				result.add(contact);
				minimum = distance;
			} else {
				if (distance <= minimum + delta) {
					distances.put(Integer.valueOf(contact.hashCode()), Integer.valueOf(distance));
					result.add(contact);
				}
			}
		}

		Collections.sort(result, new Comparator<Contact>() {
			public int compare(Contact c1, Contact c2) {
				return distances.get(c1.hashCode()).compareTo(distances.get(c2.hashCode()));
			}
		});

		return result;

	}

	public Contact getContactByNumber(String number) {
		if (number.startsWith("+")) {
			number = number.substring(3);
		}

		if (number.startsWith("00")) {
			number = number.substring(4);
		}

		for (Contact contact : getContacts()) {
			for (ContactPhone pNumber : contact.getPhones())
				if (pNumber.getNumber().endsWith(number))
					return contact;
		}
		return null;

	}
	
	/**
	 * FIXME this method is NOT working, not idea why ????
	 * 
	 * @return
	 */
	public static List<Contact> upcomingBirthday() {

	  Uri dataUri = ContactsContract.Data.CONTENT_URI;

	  String[] projection = new String[] { ContactsContract.Contacts.DISPLAY_NAME,                         
	            ContactsContract.CommonDataKinds.Event.CONTACT_ID,
	            ContactsContract.CommonDataKinds.Event.START_DATE
	            };


	  Cursor c = ContextService.inst.getApplicationContext().getContentResolver().query(
	       dataUri,
	       projection, 
	       ContactsContract.Data.MIMETYPE + "= ?" 
	       		+" AND " +    ContactsContract.CommonDataKinds.Event.TYPE + "=" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY,
	       new String[] {ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE}, null);
	  
	  List<Contact> result = new ArrayList<Contact>();
	  while (c.moveToNext()) {
	      //result.add(new Contact(c.getString(0), c.getString(1), c.getString(2)));
		  System.out.println(c.getString(0) +" - "+ c.getString(1)+" - "+ c.getString(2));
	  }
	  c.close();
	  return result;
	}

	@Override
	public String getServiceName() {
		return "contact";
	}

	@Override
	protected void _run() {

	}

	@Override
	protected void stopInternal() {
		if (getContacts() != null)
			getContacts().clear();
	}

	@Override
	protected void startInternal() {
	}

}
